'''
Created on Aug 23, 2010

@author: adolfo

Module that contains the application context configuration for the automated
tests performed on the ``core`` module of the SMSAppStore project.
'''
from springpython.config import PythonConfig, Object
import logging.handlers
from ..core import SMSAppStoreDispatcher, _Session
from ..schema_reader import ApplicationReader, FormReader
import array
from ..sms_gateway import Message
from mx.org.came.core import SessionHandler
from springpython.context import scope

_LOGGER = logging.getLogger("mx.org.came.tests.core_test_application_context")

class CoreTestConfig(PythonConfig):
    """ Base application context configuration for the implementations of SMSGateway
    in the SMSAppStore project.
    For more information, visit `Spring Python's home page
    <http://springpython.webfactional.com/>`_.
    """

    def __init__(self):
        PythonConfig.__init__(self)

    @Object
    def root_logger(self):
        """Configures the loggers to be used during testing and returns
        the root logger. This object is never explicitly used,
        since Spring Python eagerly creates it, and by doing so, the logging
        is configured"""

        LOG_FILENAME = "../target/test/core_tests.log"
        LOG_FORMAT = "%(asctime)s - [%(name)s] - [%(levelname)s] - %(message)s"

        #File logging configuration
        file_handler = logging.handlers.RotatingFileHandler(
                LOG_FILENAME,
                maxBytes=2000000,
                backupCount=5)
        file_handler.setLevel(logging.DEBUG)
        file_handler.setFormatter(logging.Formatter(LOG_FORMAT))
        logging.getLogger().addHandler(file_handler)

        #Console logging configuration
        console_handler = logging.StreamHandler()
        console_handler.setLevel(logging.INFO)
        console_handler.setFormatter(logging.Formatter(LOG_FORMAT))
        logging.getLogger().addHandler(console_handler)

        #Logging levels for the different application packages
        logging.getLogger().setLevel(logging.INFO)
        logging.getLogger("mx.org.came").setLevel(logging.DEBUG)

        return logging.getLogger()
    
    @Object(scope.PROTOTYPE)
    def application_reader(self):
        """Returns a dummy ``ApplicationReader`` that always returns the
        same dictionary.
        """
        class DummyApplicationReader(ApplicationReader):
            """``ApplicationReader`` that always returns the same
            dictionary and should only be used for testing.
            """
            def parseFile(self, application_id):
                """Returns a dictionary that describes (part of) the structure
                of a database.
                """
                app_dict = {'type': '0', 'id': '0', 'name': 'CAME'
                            , 'schemas': {u'0': {'name': 'Client'
                                                 , '0': {'range': '24'
                                                          , 'name': 'Client ID'}
                                                 , '1': {'range': '16'
                                                         , 'name': 'Group ID'}
                                                 , '3': {'range': '24'
                                                         , 'name': 'Saving'}
                                                 , '5': {'range': '18'
                                                        , 'name': 'CAME Capital'}
                                                 , '15': {'range': '10'
                                                          , 'name': 'Cycle'}
                                                 , '16': {'range': '8'
                                                          , 'name': 'Group Rate'}}}}
                return app_dict
        return DummyApplicationReader(None)
    
    @Object(scope.PROTOTYPE)
    def form_reader(self):
        """Returns a dummy ``FormReader`` that always returns the
        same dictionary.
        """
        class DummyFormReader(FormReader):
            """``FormReader`` that always returns the same
            dictionary and should only be used for testing.
            """
            def parseFile(self, application_id, form_id):
                """Returns a dictionary that describes the structure of a
                database.
                """
                form_dict = {'name': 'Dummy Form', 'logical': 'AND'
                             , 'application': '0', 'operation': '3', 'id': '0'
                             , 'schemas': {u'0': {'operator': {'1': 'Equal to'}
                                                  , 'fields': ['1']
                                                  , 'fetch': ['0', '1', '3'
                                                              , '5', '15'
                                                              , '16']}}}
                return form_dict
        return DummyFormReader(None)
    
    @Object
    def smsappstore_dispatcher(self):
        """Configures the ``SMSAppStoreDispatcher`` that will handle the
        binary messages sent by the client applications. Sets the
        instance of ``SMSGateway`` it will use and how long the threads that
        handle the communications from a given phone stay waiting (``None``
        means they wait forever). The timeout period is given in seconds.
        """
        sms_dispatcher = SMSAppStoreDispatcher(None # No gateway
                , self.application_reader()
                , self.form_reader()
                , None # No connection for SMSAppStore operations
                , session_handler_timeout = 3)
        return sms_dispatcher
    
    @Object(scope.PROTOTYPE)
    def single_packet_session(self):
        """Returns an instance of `_Session`` session that contains an operation
        that spans a single packet
        """
        message = self.single_session_message()
        packet = array.array('B'
                             , message.data[Message.ORIGINAL_BINARY_MESSAGE])
        session = _Session(packet)
        return session
    
    @Object(scope.PROTOTYPE)
    def multiple_packet_session(self):
        """Returns an instance of `_Session`` session that contains an operation
        that spans a single packet
        """
        session = _Session(array.array("B"
                             , "\x01\x01\x04\x00\x01\x01\x04\x00\x00c\xa8"))
        session.add_packet(array.array("B"
                             , "\x01\x01\x04\x01\x01\x01\x04\x00\x00c\xa8"))
        session.add_packet(array.array("B"
                             , "\x01\x01\x04\x02\x01\x01\x04\x00\x00c\xa8"))
        session.add_packet(array.array("B"
                             , "\x01\x01\x04\x03\x01\x01\x04\x00\x00c\xa8"))
        return session
    
    @Object(scope.PROTOTYPE)
    def single_session_message(self):
        """Returns an instance of ``Message`` that contains a packet witch
        describes an operation with a session that spans a single packet
        """
        message = Message()
        message.data.update({Message.SENDER_PHONE_NUMBER : "2381280921"
                , Message.UDH : "\x06\x05\x04\xdf\x8b\x00\x00"
                , Message.ORIGINAL_BINARY_MESSAGE : 
                        "\x01\x00\x01\x00\x01\x01\x04\x00\x00\x63\xa8"})
        return message
    